Redux
Redux 的基本思想是整个应用的 state 保持在一个单一的 store 中。store 是一个简单的 js 对象,而改变应用 state 的唯一方式是在应用中触发 actions,然后为这些 actions 编写 reducers 来修改 state。整个 state 转化是在 reducers 中完成,并且不应该有任何副作用。
Redux 分为三大部分,store, action , reducer。
工作流程是:
- view 用 actionCreator 创建一个 action,里面可能包含一些数据
- 使用 store 的 dispatch 方法将 action 传入 store
- store 将 action 与旧的 state 转发给 reducer
- reducer 深拷贝 state,并返回一个新的 state 给 store
- store 接收并更新 state
- 使用 store.subscribe 订阅更新,重新 render 组件
有两个非常突出的特点:
- predictable 可预测性。可预测性是由于它大量使用 pure function 和 plain object 等概念(reducer 和 action creator 是 pure function, state 和 action 是 plain object),并且 state 是 immutable 的。 这对于项目的稳定性会是很好的保证。
- 可扩展性。可扩展性则让我们可通过 middleware 定制 action 的处理,通过 reducer enhancer 扩展 reducer 等等。从而有了丰富的社区扩展和支持,比如异步处理,Form,router 同步, redu/ubdo ,性能问题(selecter), 工具支持等。
Redux 遵循三个基本原则
- 单一数据来源: 整个应用程序的状态存储在单个对象树中。单状态树可以更容易地跟踪随时间的变化并调试或检查应用程序。
- 状态是只读的: 改变状态的唯一方法是发出一个动作,一个描述发生的事情的对象。这可以确保视图和网络请求都不会直接写入状态。
- 使用纯函数进行更改: 要指定状态树如何通过操作进行转换,您可以编写 reducers。Reducers 只是纯函数,它将先前的状态和操作作为参数,并返回下一个状态。
使用 redux 的步骤
- 安装 redux
- 创建文件夹、reducers 文件夹(先创建)、action 文件夹、store.js 文件
- 可能 reducers 文件里面不只一个 reduce,所以要在 reducers 文件里面的 index.js 里面去导入一下 combineReducers
import { combineReducers } from "redux";
import cart from "./cart";
export default combineReducers({
cart,
});
Store
Store 是一个对象,它保存了整个应用的 state。与此同时,Store 也承担以下职责:
- 允许通过
getState()访问 state - 运行通过
dispatch(action)改变 state - 通过
subscribe(listener)注册 listeners,通过subscribe(listener)返回的函数处理 listeners 的注销
只需要使用createStore()从它创建的模块中导出存储。此外,它不应污染全局窗口对象。
store = createStore(myReducer);
export default store;
Action
Actions是纯 JavaScript 对象或信息的有效负载,可将数据从您的应用程序发送到您的 Store。 Action 必须具有指示正在执行的操作类型的 type 属性。
例如,表示添加新待办事项的示例操作:
{
type: ADD_TODO,
text: 'Add todo item'
}
Reducer
一个 reducer 是一个纯函数,该函数以先前的 state 和一个 action 作为参数,并返回下一个 state。
redux 的另一个缺点是:reducer 要求每次返回一个新的对象引用。当需要修改的数据层级较深,reducer 写起来很难保证优雅。所以一般 redux 项目都会刻意的保持 store 的扁平化,没有深层级的数据,用 Object.assign 浅拷贝处理。
redux 缺点
重绘
redux 的缺点也是足够明显的。每一次 dispatch 事件之后都会导致整个虚拟 dom 至顶向下的重绘。重绘剪枝需要在 shouldComponentUpdate中完成,如果事件足够复杂, store 足够大,shouldComponentUpdate方法的剪枝粒度就不那么容易控制。
- 一个组件所需要的数据,必须由父组件传过来,不能像 flux 中直接从 store 取。
- 当一个组件相关数据更新时,即使父组件不需要用到这个组件,父组件还是会重新 render,可能会有效率影响,或者需要写复杂的
shouldComponentUpdate进行判断。
react-redux
使用
react-redux中的<Provider>来绑定全局的一个 store;使用
react-redux中的connect来创建容器组件。redux connect state -> props
mapDispatchToProps action-> props